//alu.c

 /*
 * Team Name: Focus
 * Team Members: Diana Groun, Edward Bassan
 * File Name; memory.c
 * Description: This file contains the methods that memory uses such as store and fetch
 */
#include<stdio.h>
#include<stdlib.h>
#include"memory.h"
#include "global.h"

/*
 * Constructor
 */
MemoryPtr newMemory() {
	MemoryPtr newMem = (MemoryPtr) malloc(sizeof(Memory));
	int i;
	for (i = 0; i < MEM_SIZE; i++) {
		newMem->memory[i] = 0x00;
	}
	newMem->storeByte = memoryStoreByte;
	newMem->storeWord = memoryStoreWord;
	newMem->displayMemory = displayMemory;
	newMem->fetchByte = memoryFetchByte;
	newMem->fetchWord = memoryFetchWord;
	return newMem;
}

/*
 * Return the byte value at the memory address
 */
Byte memoryFetchByte(MemoryPtr mem, int address) {
	if (mem == NULL ) {
		return NULL_POINTER_ERROR;
	} else if ((address - MEMORY_OFFSET < 0) | (address - MEMORY_OFFSET >= 150)) {
		return INDEX_OUT_OF_BOUNDS;
	}
	return mem->memory[address - MEMORY_OFFSET];
}

/*
 * Return the word value formed by combining the byte value from the given memory address with the byte from the nex memory adress
 * The adress has to been an even number
 */
Word memoryFetchWord(MemoryPtr mem, int adress) {
	if (mem == NULL ) {
		return NULL_POINTER_ERROR;
	} else if (adress < MEMORY_OFFSET) {
		return ADRESS_ERROR;
	} else if (adress >= MEMORY_OFFSET + BEGENING_OF_STACK) {
		return ADRESS_ERROR;
	} else if (adress % 2 != 0) {
		return ADRESS_ERROR;
	}
	Word value = mem->memory[adress - MEMORY_OFFSET]*256;
	value = value | mem->memory[(adress+1)-MEMORY_OFFSET];
	return value;
}

/*
 * Stores the given byte to the given location
 */
int memoryStoreByte(MemoryPtr memoryMod, int adress, Byte value) {
	if (memoryMod == (MemoryPtr) NULL ) {
		return NULL_POINTER_ERROR;
	} else if (adress < MEMORY_OFFSET) {
		return INDEX_OUT_OF_BOUNDS;
	} else if (adress > BEGENING_OF_STACK + MEMORY_OFFSET) {
		return INDEX_OUT_OF_BOUNDS;
	}
	memoryMod->memory[adress - MEMORY_OFFSET] = value;
	return NO_ERROR;
}

/**
 * Stores a word by storing the hob into the given memory location and the lob inot the next memory location.
 * The given memory address has to be and even number.
 *
 */
int memoryStoreWord(MemoryPtr memoryMod, int adress, Word value) {
	if (memoryMod == (MemoryPtr) NULL ) {
		return NULL_POINTER_ERROR;
	} else if (adress < MEMORY_OFFSET) {
		return INDEX_OUT_OF_BOUNDS;
	} else if (adress > BEGENING_OF_STACK + MEMORY_OFFSET) {
		return INDEX_OUT_OF_BOUNDS;
	} else if (adress % 2 != 0) {
		return ADRESS_ERROR;
	}
	Byte lob_val = LOB_MASK & value;
	Word hob_val = HOB_MASK & value;
	hob_val = hob_val /256;
	memoryMod->memory[adress - MEMORY_OFFSET] = hob_val;
	memoryMod->memory[(adress + 1) - MEMORY_OFFSET] = lob_val;
	return 0;
}

/**
 * Displays the memory from 0x3000 to 0x3094
 */
int displayMemory(MemoryPtr mem) {
	int i;
	for (i = 0; i < 150; i = i + 2) {
		printf("%.4X: %.2X %.2X\n", i + MEMORY_OFFSET, mem->memory[i],
				mem->memory[i + 1]);
	}
	return 0;
}
int dispalyMemoryLocation(MemoryPtr mem, int bgn, int end) {
	int i;
	int temp = bgn - MEMORY_OFFSET;
	if (bgn % 2 != 0) {
		temp = (bgn - 1) - MEMORY_OFFSET;
	}
	for (i = temp; i <= end - MEMORY_OFFSET; i = i + 2) {
		printf("%.4X: %.2X %.2X\n", i + MEMORY_OFFSET, mem->memory[i],
				mem->memory[i + 1]);
	}
	return 0;
}
/*
 * tests for memory
 */
/*
int main() {
	MemoryPtr m = newMemory();
	printf("Storing a byte in an address too small: %X\n",
			m->storeByte(m, 0x2FF5, 0x04));
	printf("Storing a byte in an address too big: %X\n",
			m->storeByte(m, 0x3001 + BEGENING_OF_STACK, 0x04));
	printf("Storing a byte in an address with in bounds: %X\n",
			m->storeByte(m, 0x300F, 0x04));
	dispalyMemoryLocation(m, 0x300E, 0x3010);
	printf("Storing a word in an address too small: %X\n",
			m->storeWord(m, 0x2FF5, 0x3fd4));
	printf("Storing a word in an address too big: %X\n",
			m->storeWord(m, 0x2FFF + BEGENING_OF_STACK, 0x3fd4));
	printf("Storing a word in an odd address: %X\n",
			m->storeWord(m, 0x3009, 0x3fd4));
	printf("Storing a word in an even address: %X\n",
				m->storeWord(m, 0x301A, 0x3fd4));
	dispalyMemoryLocation(m, 0x3018, 0x301C);

	printf("Fetching a byte from an address too small: %X\n",
				m->fetchByte(m, 0x2FFF));
		printf("Fetching a byte from an address too big: %X\n",
				m->fetchByte(m, 0x3000 + BEGENING_OF_STACK));
		printf("Fetching a byte from an address with in bounds: %X\n",
				m->fetchByte(m, 0x300F));

		printf("Fetching a word from an address too small: %X\n",
				m->fetchWord(m, 0x2FFF));
		printf("Fetching a word from an address too big: %X\n",
				m->fetchWord(m, 0x3000 + BEGENING_OF_STACK));
		printf("Fetching a word from an odd address: %X\n",
				m->fetchWord(m, 0x3009));
		printf("Fetching word from an even address: %X\n",
					m->fetchWord(m, 0x301A));
		dispalyMemoryLocation(m, 0x3018, 0x301C);

	return 0;
}
*/

